package org.fujay.commons.langchain4j.rag.processor.result;

import dev.langchain4j.model.output.TokenUsage;
import lombok.Builder;
import lombok.Data;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author slm
 * @description 文档处理结果
 * 包含文档处理的统计信息和元数据
 */
@Data
@Builder
public class DocumentProcessResult {

    /**
     * 处理开始时间
     */
    private LocalDateTime startTime;

    /**
     * 处理结束时间
     */
    private LocalDateTime endTime;

    /**
     * 处理的文档数量
     */
    private int documentCount;

    /**
     * 生成的文本段数量
     */
    private int segmentCount;

    /**
     * 处理过程中产生的令牌使用情况
     */
    private TokenUsage tokenUsage;

    /**
     * 成功处理的文档数量
     */
    private int successCount;

    /**
     * 处理失败的文档数量
     */
    private int failureCount;

    /**
     * 处理中跳过的文档数量
     */
    private int skippedCount;

    /**
     * 文档ID列表
     */
    private List<String> documentIds;

    /**
     * 处理过程中产生的错误（如果有）
     */
    private List<Exception> errors;

    /**
     * 处理的总字符数
     */
    private long totalCharacters;

    /**
     * 创建带开始时间的构建器
     *
     * @return 构建器实例
     */
    public static DocumentProcessResultBuilder builder() {
        return new DocumentProcessResultBuilder().startTime(LocalDateTime.now());
    }

    /**
     * 创建一个空的结果对象
     *
     * @return 空的结果对象
     */
    public static DocumentProcessResult empty() {
        return DocumentProcessResult.builder()
                .documentCount(0)
                .segmentCount(0)
                .successCount(0)
                .failureCount(0)
                .skippedCount(0)
                .build();
    }

    /**
     * 合并多个处理结果
     *
     * @param results 要合并的结果列表
     * @return 合并后的结果
     */
    public static DocumentProcessResult merge(List<DocumentProcessResult> results) {
        if (results == null || results.isEmpty()) {
            return empty();
        }

        DocumentProcessResultBuilder builder = DocumentProcessResult.builder();
        LocalDateTime earliestStart = null;
        LocalDateTime latestEnd = null;
        int documentCount = 0;
        int segmentCount = 0;
        int successCount = 0;
        int failureCount = 0;
        int skippedCount = 0;
        long totalCharacters = 0;
        List<String> allDocumentIds = new ArrayList<>();
        List<Exception> allErrors = new ArrayList<>();

        // 合并令牌使用情况
        int promptTokens = 0;
        int completionTokens = 0;
        int totalTokens = 0;

        for (DocumentProcessResult result : results) {
            // 处理时间
            if (earliestStart == null || (result.startTime != null && result.startTime.isBefore(earliestStart))) {
                earliestStart = result.startTime;
            }
            if (latestEnd == null || (result.endTime != null && result.endTime.isAfter(latestEnd))) {
                latestEnd = result.endTime;
            }

            // 合并计数
            documentCount += result.documentCount;
            segmentCount += result.segmentCount;
            successCount += result.successCount;
            failureCount += result.failureCount;
            skippedCount += result.skippedCount;
            totalCharacters += result.totalCharacters;

            // 合并列表
            if (result.documentIds != null) {
                allDocumentIds.addAll(result.documentIds);
            }
            if (result.errors != null) {
                allErrors.addAll(result.errors);
            }

            // 合并令牌使用情况
            if (result.tokenUsage != null) {
                promptTokens += result.tokenUsage.inputTokenCount();
                completionTokens += result.tokenUsage.outputTokenCount();
                totalTokens += result.tokenUsage.totalTokenCount();
            }
        }

        return builder
                .startTime(earliestStart)
                .endTime(latestEnd)
                .documentCount(documentCount)
                .segmentCount(segmentCount)
                .successCount(successCount)
                .failureCount(failureCount)
                .skippedCount(skippedCount)
                .totalCharacters(totalCharacters)
                .documentIds(allDocumentIds)
                .errors(allErrors)
                .tokenUsage(new TokenUsage(promptTokens, completionTokens, totalTokens))
                .build();
    }

    /**
     * 获取处理持续时间
     *
     * @return 处理持续时间
     */
    public Duration getDuration() {
        if (startTime != null && endTime != null) {
            return Duration.between(startTime, endTime);
        }
        return Duration.ZERO;
    }

    /**
     * 获取每分钟处理的文档数
     *
     * @return 每分钟处理的文档数
     */
    public double getDocumentsPerMinute() {
        Duration duration = getDuration();
        if (duration.isZero() || documentCount == 0) {
            return 0;
        }
        double minutes = duration.toMillis() / 60000.0;
        return documentCount / minutes;
    }

    /**
     * 获取处理成功率
     *
     * @return 处理成功率（0-1之间的小数）
     */
    public double getSuccessRate() {
        if (documentCount == 0) {
            return 0;
        }
        return (double) successCount / documentCount;
    }
}